`include "mycpu.h"

module MEM_stage(
    input                          clk           ,
    input                          reset         ,
    //allowin
    input                          ws_allowin    ,
    output                         ms_allowin    ,
    output                         ms_will_to_ws  ,
    //from es
    input                          es_to_ms_valid,
    input                          es_to_ms_cancel_first_back,
    output                         ms_to_es_flush,
    input  [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus  ,//71
    // input  [32:0]                  es_to_ms_data_bus,
    output                         ms_to_es_data_alok,
    output                         ms_to_es_data_alok2,      
    //to ws
    output                         ms_to_ws_valid,
    output [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus  ,//70
    //to ds
    output [`_TO_DS_BUS_WD   -1:0] ms_to_ds_bus ,
    output [32:0]                   ms_to_cr_bus,
    //from data-sram
    input  [63                 :0] data_sram_rdata,
    input                          data_sram_data_ok,
    input                          data_sram_addr_ok,
    input                          data_sram_req,
    output [`MS_TO_TH_BUS_WD -1:0]   ms_to_th_bus,
    // output                         ms_to_es_ex,
    // output                         ms_to_fs_ex,
    input                           cr_flush_o
);



reg         ms_valid;
reg         data_alok;
// reg         cancel_first_back;
reg [1:0]        count;
reg         data_alok2;
// reg [31:0]  rdata_buf;
// reg [31:0]  rdata_buf2;
reg [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus_r;

wire       cancel_first_back;
assign     cancel_first_back = es_to_ms_cancel_first_back;

wire        ms_ready_go;
wire        ms_res_from_mem;
wire        ms_gr_we;
wire        op_lw;
wire        op_lb;
wire        op_lbu;
wire        op_lh;
wire        op_lhu;
wire        op_lwu;
wire        op_ld;
wire        ms_load_or_store;
wire [4:0]  ms_dest;
wire [6:0]  ms_load_op_clear;
wire [63:0] ms_alu_result;
wire [63:0] ms_rs1_value;
wire [63:0] ms_pc;

wire [63:0] mem_result;
wire [63:0] ms_final_result;
wire [63:0] rdata;
wire [31:0] ms_inst;
wire        ms_load_op;
wire        ms_0x7b;

////csr////
wire[11:0] csr_addr;
wire[4:0] ms_zimm;
wire        ms_int;
wire        ms_ex;
wire  ms_csrrw ; 
wire  ms_csrrs ;
wire  ms_csrrc ;
wire  ms_csrrwi;
wire  ms_csrrsi;
wire  ms_csrrci;
wire  ms_mret;
wire  ms_skip_clint;
wire  ms_op_csr;

assign ms_op_csr  = ms_csrrw   ||  ms_csrrs  ||  ms_csrrc  ||  ms_csrrwi ||  ms_csrrsi ||  ms_csrrci; 
assign ms_to_es_flush =(ms_ex || ms_int || ms_mret) && ms_valid;

assign rdata = data_sram_rdata;
assign {
                        ms_int,
                        ms_ex,
                        ms_mret,
                        ms_csrrw ,
                        ms_csrrs ,
                        ms_csrrc ,
                        ms_csrrwi,
                        ms_csrrsi,
                        ms_csrrci,                        
                        ms_zimm,
                        csr_addr,
        ms_0x7b,
        ms_load_op, //141
        ms_load_or_store,//140
        ms_load_op_clear,
        ms_res_from_mem,  //70:70
        ms_gr_we       ,  //69:69
        ms_dest        ,  //68:64
        ms_rs1_value   ,
        ms_alu_result  ,  //63:32
        ms_inst        ,
        ms_pc             //31:0
       } = es_to_ms_bus_r;
assign ms_to_ws_bus = {
                        ms_skip_clint,
                        ms_int,
                        ms_ex,
                        ms_mret,
                        ms_csrrw ,
                        ms_csrrs ,
                        ms_csrrc ,
                        ms_csrrwi,
                        ms_csrrsi,
                        ms_csrrci,                        
                        ms_zimm,
                        csr_addr, 
                        ms_0x7b,
                        ms_gr_we       ,  //133:133
                        ms_dest        ,  //132:128
                        ms_rs1_value   ,
                        ms_final_result,  //127:64
			            ms_inst,
                        ms_pc             //63:0
                      };

//
assign ms_to_th_bus = {
                        ms_op_csr,//9
                        ms_ready_go,//8
                        ms_load_op,//7
                        ms_valid,//6:6
                        ms_gr_we, //5:5
                        ms_dest    //4:0
                        };


assign ms_to_ds_bus ={
                        ms_to_ws_valid, //70:70
                        ms_gr_we , //69:69
                        ms_dest,        //68:64
                        ms_final_result //63:0
                        };



assign ms_ready_go    =  ~ms_load_or_store  
                      ||  ms_load_or_store && ( data_sram_data_ok ) && ~cancel_first_back
                      || ms_ex && ms_valid;
assign ms_allowin     = !ms_valid || ms_ready_go && ws_allowin;
assign ms_to_ws_valid = ms_valid && ms_ready_go;
assign ms_will_to_ws  = ms_ready_go && ws_allowin;

// assign count_add = data_sram_req && data_sram_addr_ok && !data_sram_data_ok;
// assign count_sub = data_sram_data_ok && !( data_sram_req && data_sram_addr_ok);
assign ms_to_es_data_alok         = data_alok;
assign ms_to_es_data_alok2         =data_alok2;
always @(posedge clk) begin
    if (reset | cr_flush_o) begin
        ms_valid <= 1'b0;
    end
    else if (ms_allowin) begin
        ms_valid <= es_to_ms_valid;
    end

    if (es_to_ms_valid && ms_allowin) begin
        es_to_ms_bus_r  <= es_to_ms_bus; //要非阻塞赋�?�，本来是阻塞赋�??//Error_06
    end
    //////////////////////
    if ( ms_ready_go && ws_allowin || cr_flush_o || reset) begin
        data_alok <= 1'b0;
    end

    else  if (data_sram_data_ok && !ms_allowin &&~cancel_first_back && !data_alok2) begin
        data_alok <= 1'b1;
        // rdata_buf <= inst_sram_rdata;
    end
    if (reset || data_alok2 && ms_ready_go  && ws_allowin && !data_alok||  cr_flush_o) begin
        data_alok2 <= 1'b0;
    end
    else if (data_alok  && data_sram_data_ok) begin
        data_alok2 <= 1'b1;
        // rdata_buf2 <= rdata;

    end

    //  if (data_sram_data_ok || !ms_allowin &&  !data_alok)
    //  rdata_buf <= rdata;
end

assign   op_lw  = ms_load_op_clear [0];
assign   op_lb  = ms_load_op_clear [1];
assign   op_lbu = ms_load_op_clear [2];
assign   op_lh  = ms_load_op_clear [3];
assign   op_lhu = ms_load_op_clear [4];
assign   op_lwu = ms_load_op_clear [5];
assign   op_ld  = ms_load_op_clear [6];
wire  [2:0] offset;
wire  [7:0] sel;
assign   offset = ms_alu_result[2:0];
decoder_3_8   u_dec1(.in(offset),    .out(sel));

                    
assign mem_result = ({64{op_ld  }}     & rdata)
                  | ({64{op_lw  &  sel[3'h0]}}     & {{32{rdata[31]}},rdata[31:00]})
                  | ({64{op_lw  &  sel[3'h4]}}     & {{32{rdata[63]}},rdata[63:32]})
                  | ({64{op_lwu &  sel[3'h0]}}     & {{32'b0        },rdata[31:00]})
                  | ({64{op_lwu &  sel[3'h4]}}     & {{32'b0        },rdata[63:32]})
                  | ({64{op_lh  &  sel[3'h0]}}     & {{48{rdata[15]}},rdata[15:00]})
                  | ({64{op_lh  &  sel[3'h2]}}     & {{48{rdata[31]}},rdata[31:16]})
                  | ({64{op_lh  &  sel[3'h4]}}     & {{48{rdata[47]}},rdata[47:32]})
                  | ({64{op_lh  &  sel[3'h6]}}     & {{48{rdata[63]}},rdata[63:48]})
                  | ({64{op_lhu &  sel[3'h0]}}     & {{48'b0        },rdata[15:00]})
                  | ({64{op_lhu &  sel[3'h2]}}     & {{48'b0        },rdata[31:16]})
                  | ({64{op_lhu &  sel[3'h4]}}     & {{48'b0        },rdata[47:32]})
                  | ({64{op_lhu &  sel[3'h6]}}     & {{48'b0        },rdata[63:48]})
                  | ({64{op_lb  &  sel[3'h0]}}     & {{56{rdata[07]}},rdata[07:00]})
                  | ({64{op_lb  &  sel[3'h1]}}     & {{56{rdata[15]}},rdata[15:08]})
                  | ({64{op_lb  &  sel[3'h2]}}     & {{56{rdata[23]}},rdata[23:16]})
                  | ({64{op_lb  &  sel[3'h3]}}     & {{56{rdata[31]}},rdata[31:24]})
                  | ({64{op_lb  &  sel[3'h4]}}     & {{56{rdata[39]}},rdata[39:32]})
                  | ({64{op_lb  &  sel[3'h5]}}     & {{56{rdata[47]}},rdata[47:40]})
                  | ({64{op_lb  &  sel[3'h6]}}     & {{56{rdata[55]}},rdata[55:48]})
                  | ({64{op_lb  &  sel[3'h7]}}     & {{56{rdata[63]}},rdata[63:56]})
                  | ({64{op_lbu &  sel[3'h0]}}     & {{56'b0        },rdata[07:00]})
                  | ({64{op_lbu &  sel[3'h1]}}     & {{56'b0        },rdata[15:08]})
                  | ({64{op_lbu &  sel[3'h2]}}     & {{56'b0        },rdata[23:16]})
                  | ({64{op_lbu &  sel[3'h3]}}     & {{56'b0        },rdata[31:24]})
                  | ({64{op_lbu &  sel[3'h4]}}     & {{56'b0        },rdata[39:32]})
                  | ({64{op_lbu &  sel[3'h5]}}     & {{56'b0        },rdata[47:40]})
                  | ({64{op_lbu &  sel[3'h6]}}     & {{56'b0        },rdata[55:48]})
                  | ({64{op_lbu &  sel[3'h7]}}     & {{56'b0        },rdata[63:56]});
                //   | ({64{op_lbu }}     & {{56'b0        },rdata[07:0]})

assign ms_final_result = ms_res_from_mem ? mem_result:ms_alu_result;
assign ms_skip_clint   = ms_valid && ms_load_or_store 
                        && (ms_alu_result == 64'h0000_0000_0200_4000 
                        || ms_alu_result == 64'h0000_0000_0200_bff8 );
                                                

endmodule
